package com.usian.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.usian.config.RedisClient;
import com.usian.mapper.*;
import com.usian.pojo.*;
import com.usian.service.ItemService;
import com.usian.utils.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Transactional
public class ItemServiceImpl implements ItemService {

    @Autowired
    private TbItemMapper tbItemMapper;

    /*@Autowired
    private TbItemParamMapper tbItemParamMapper;*/

    @Autowired
    private TbItemParamItemMapper tbItemParamItemMapper;

    @Autowired
    private TbOrderItemMapper tbOrderItemMapper;

    @Autowired
    private TbItemDescMapper tbItemDescMapper;

    @Autowired
    private TbItemCatMapper tbItemCatMapper;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private RedisClient redisClient;

    @Value("${ITEM_INFO}")
    private String ITEM_INFO;

    @Value("${BASE}")
    private String BASE;

    @Value("${DESC}")
    private String DESC;

    @Value("${PARAM}")
    private String PARAM;

    @Value("${ITEM_INFO_EXPIRE}")
    private Long ITEM_INFO_EXPIRE;

    @Value("${SETNX_BASC_LOCK_KEY}")
    private String SETNX_BASC_LOCK_KEY;

    @Value("${SETNX_DESC_LOCK_KEY}")
    private String SETNX_DESC_LOCK_KEY;

    /**
     * 根据id查找Item
     * @param id
     * @return
     */
    @Override
    public TbItem findItemById(Long id) {
        /* 缓存中获取 缓存中存在直接返回 */
        TbItem tbItemRedis =(TbItem) redisClient.get(ITEM_INFO + ":" + BASE + ":" + id);
        if (tbItemRedis!=null){
            return tbItemRedis;
        }

        /* 添加分布式锁解决缓存击穿问题 */
        if (redisClient.setnx(SETNX_BASC_LOCK_KEY+":"+id,id,30L)){

            /* 缓存中不存在  去数据库中查询 判断数据库中是否存在 防止缓存穿透问题 */
            TbItem tbItem = tbItemMapper.selectByPrimaryKey(id);
            if (tbItem==null){
                /* 如果不存在  设置一个空数据 */
                tbItem = new TbItem(id,"数据有误");
            }
            redisClient.set(ITEM_INFO+":"+BASE+":"+id,tbItem);
            redisClient.expire(ITEM_INFO+":"+BASE+":"+id,ITEM_INFO_EXPIRE);

            /* 处理完成 删除锁 */
            redisClient.del(SETNX_BASC_LOCK_KEY+":"+id);
            return tbItem;
        }else {
            /* 等待0.1秒 重新尝试获取锁 */
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return findItemById(id);
        }
    }

    /**
     * 分页查询所有item
     * @param page
     * @param rows
     * @return
     */
    @Override
    public PageResult selectTbItemAllByPage(Integer page, Integer rows) {
        PageHelper.startPage(page,rows);

        TbItemExample example = new TbItemExample();
        TbItemExample.Criteria criteria = example.createCriteria();
        criteria.andStatusEqualTo((byte)1);
        example.setOrderByClause("created desc");
        List<TbItem> list = tbItemMapper.selectByExample(example);
        PageInfo<TbItem> pageInfo = new PageInfo<>(list);

        PageResult pageResult = new PageResult();
        pageResult.setPageIndex(pageInfo.getPageNum());
        pageResult.setTotalPage(pageInfo.getPages());
        pageResult.setResult(pageInfo.getList());
        return pageResult;
    }

    /**
     * 添加item
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Boolean insertTbItem(TbItem tbItem, String desc, String itemParams) {
        long itemId = IDUtils.genItemId();
        tbItem.setId(itemId);
        tbItem.setCreated(new Date());
        tbItem.setUpdated(new Date());
        tbItem.setStatus((byte)1);
        tbItem.setPrice(tbItem.getPrice()*100);
        int insertTbItem = tbItemMapper.insert(tbItem);
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setItemId(itemId);
        tbItemDesc.setItemDesc(desc);
        tbItemDesc.setCreated(new Date());
        tbItemDesc.setUpdated(new Date());
        int insertitemDesc = tbItemDescMapper.insert(tbItemDesc);
        /*TbItemParam tbItemParam = new TbItemParam();
        tbItemParam.setItemCatId(tbItem.getCid());
        tbItemParam.setCreated(new Date());
        tbItemParam.setUpdated(new Date());
        int insertTbItemParam = tbItemParamMapper.insert(tbItemParam);*/
        TbItemParamItem tbItemParamItem = new TbItemParamItem();
        tbItemParamItem.setItemId(itemId);
        tbItemParamItem.setParamData(itemParams);
        tbItemParamItem.setCreated(new Date());
        tbItemParamItem.setUpdated(new Date());
        int insertTbItemParamItem = tbItemParamItemMapper.insert(tbItemParamItem);

        if (insertTbItem+insertitemDesc+insertTbItemParamItem==3){
            /* 添加成功向RabbitMQ发送信息更新数据 */
            amqpTemplate.convertAndSend("item_exchage","item.add",tbItem.getId());
            return true;
        }
        return false;
    }

    /**
     * 根据id删除Item
     * @param itemId
     * @return
     */
    @Override
    public Boolean deleteItemById(String itemId) {
        TbItem tbItem = new TbItem();
        tbItem.setStatus((byte)3);
        tbItem.setId(Long.parseLong(itemId));
        int i = tbItemMapper.updateByPrimaryKeySelective(tbItem);
        if (i==1){
            return true;
        }
        return false;
    }

    /**
     * 修改回显
     * @param itemId
     * @return
     */
    @Override
    public PreUpdate preUpdateItem(Long itemId) {
        TbItem tbItem = tbItemMapper.selectByPrimaryKey(itemId);
        TbItemCat tbItemCat = tbItemCatMapper.selectByPrimaryKey(tbItem.getCid());
        TbItemDesc tbItemDesc = tbItemDescMapper.selectByPrimaryKey(itemId);
        TbItemParamItemExample example = new TbItemParamItemExample();
        TbItemParamItemExample.Criteria criteria = example.createCriteria();
        criteria.andItemIdEqualTo(itemId);
        List<TbItemParamItem> tbItemParamItems = tbItemParamItemMapper.selectByExampleWithBLOBs(example);

        PreUpdate preUpdate = new PreUpdate();
        preUpdate.setItem(tbItem);
        preUpdate.setItemCat(tbItemCat.getName());
        preUpdate.setItemDesc(tbItemDesc.getItemDesc());
        preUpdate.setItemParamItem(tbItemParamItems.get(0).getParamData());
        return preUpdate;
    }

    /**
     * 修改item
     * @param tbItem
     * @param desc
     * @param itemParams
     * @return
     */
    @Override
    public Boolean updateTbItem(TbItem tbItem, String desc, String itemParams) {
        /* 修改item表 */
        tbItem.setUpdated(new Date());
        tbItem.setStatus((byte)1);
        tbItem.setPrice(tbItem.getPrice()*100);
        int updateItem = tbItemMapper.updateByPrimaryKeySelective(tbItem);

        /* 修改desc */
        TbItemDesc tbItemDesc = new TbItemDesc();
        tbItemDesc.setUpdated(new Date());
        tbItemDesc.setItemId(tbItem.getId());
        tbItemDesc.setItemDesc(desc);
        int updateItemDesc = tbItemDescMapper.updateByPrimaryKeySelective(tbItemDesc);

        /* 修改itemparamItem表 */
        TbItemParamItem tbItemParamItem = new TbItemParamItem();
        tbItemParamItem.setUpdated(new Date());
        tbItemParamItem.setParamData(itemParams);
        TbItemParamItemExample example = new TbItemParamItemExample();
        TbItemParamItemExample.Criteria criteria = example.createCriteria();
        criteria.andItemIdEqualTo(tbItem.getId());
        int updateItemParamItem = tbItemParamItemMapper.updateByExampleSelective(tbItemParamItem, example);
        if (updateItem+updateItemDesc+updateItemParamItem==3){
            return true;
        }
        return false;
    }

    /**
     * 根据id查询描述信息
     * @param itemId
     * @return
     */
    @Override
    public TbItemDesc selectItemDescByItemId(Long itemId) {
        /* 缓存中查询 如果存在直接返回 */
        TbItemDesc tbItemDescRedis = (TbItemDesc) redisClient.get(ITEM_INFO+":"+DESC+":"+itemId);
        if (tbItemDescRedis!=null){
            return tbItemDescRedis;
        }

        /* 通过setnx实现添加分布式锁防止缓存击穿问题 并设置一个过期时间 防止死锁现象 */
        if (redisClient.setnx(SETNX_DESC_LOCK_KEY+":"+itemId,itemId,30L)){
            /* 缓存中不存在去数据库查询 */
            TbItemDesc tbItemDesc = tbItemDescMapper.selectByPrimaryKey(itemId);
            /* 判断数据库中是否存在 不存在就缓存一个空数据防止缓存穿透问题 */
            if (tbItemDesc==null){
                tbItemDesc = new TbItemDesc(itemId,"数据有误");
            }
            redisClient.set(ITEM_INFO+":"+DESC+":"+itemId,tbItemDesc);
            redisClient.expire(ITEM_INFO+":"+DESC+":"+itemId,ITEM_INFO_EXPIRE);

            /* 处理完成 删除锁 */
            redisClient.del(SETNX_DESC_LOCK_KEY+":"+itemId);
            return tbItemDesc;
        }else {
            /* 没有抢到锁 休眠0.1s 继续抢到锁资源 */
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return  selectItemDescByItemId(itemId);
        }
    }

    /**
     * 修改商品库存数量
     * @param orderId
     * @return
     */
    @Override
    public Integer updateTbItemByOrderId(String orderId) {
        int result = 0;
        try {
            /* 查询订单信息 */
            TbOrderItemExample example = new TbOrderItemExample();
            TbOrderItemExample.Criteria criteria = example.createCriteria();
            criteria.andOrderIdEqualTo(orderId);
            List<TbOrderItem> tbOrderItems = tbOrderItemMapper.selectByExample(example);
            for (TbOrderItem tbOrderItem : tbOrderItems) {
                /* 查找商品 */
                TbItem tbItem = tbItemMapper.selectByPrimaryKey(Long.valueOf(tbOrderItem.getItemId()));
                /* 校验数量 */
                if (tbItem.getNum()>0 && tbItem.getNum()>=tbOrderItem.getNum()){
                    /* 减库存 */
                    tbItem.setNum(tbItem.getNum()-tbOrderItem.getNum());
                    tbItem.setUpdated(new Date());
                    /* 更新表中数据 */
                    result += tbItemMapper.updateByPrimaryKeySelective(tbItem);
                }
            }

        } catch (NumberFormatException e) {
            e.printStackTrace();
            System.out.println("减库存异常");
            return 0;
        }
        return result;
    }


}
